﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace TileMap
{
    class TifHeightFile
    {
        private static readonly object LockObject = new object();
        private static readonly string SourceFilePath = "HeightMapSource/";

        private static readonly Dictionary<string, int[]> mapDatas = new Dictionary<string, int[]>();

        private static readonly int RasterXSize = 6001;
        private static readonly int RasterYSize = 6001;


        public static void Clear()
        {
            mapDatas.Clear();
        }

        public static float GetHeight(double lon, double lat)
        {
            int[] map = null;
            string file = GeneralFileName(lon, lat, out double left, out double top);
            lock (LockObject)
            {
                if (!mapDatas.ContainsKey(file))
                {
                    LoadMap(file);
                }
                map = mapDatas[file];
            };
            double x = (lon - left) / (5.0f / RasterXSize);
            double y = (top - lat) / (5.0 / RasterYSize);
            int l = (int)Math.Floor(x);
            int t = (int)Math.Floor(y);
            int r = (int)Math.Min(Math.Ceiling(x), RasterXSize - 1);
            int b = (int)Math.Min(Math.Ceiling(y), RasterYSize - 1);

            int[] v = new int[4];
            v[0] = map[t * RasterXSize + l];
            v[1] = map[t * RasterXSize + r];
            v[2] = map[b * RasterXSize + l];
            v[3] = map[b * RasterXSize + r];

            float height = 0;
            for (int i = 0; i < v.Length; ++i)
            {
                if (v[i] != -32768)
                {
                    height += v[i];
                }
            }

            return height / v.Length;
        }

        private static string GeneralFileName(double lon, double lat, out double left, out double top)
        {
            double baseLat = 60;
            double baseLon = -180;

            int x = (int)Math.Floor((lon - baseLon) / 5.0) + 1;
            int y = (int)Math.Floor((baseLat - lat) / 5.0) + 1;

            left = (x - 1) * 5 + baseLon;
            top = -(y - 1) * 5 + baseLat;

            return SourceFilePath + string.Format("srtm_{0:D2}_{1:D2}.tif", x, y);
        }

        private static void LoadMap(string file)
        {
            var dataset = OSGeo.GDAL.Gdal.Open(file, OSGeo.GDAL.Access.GA_ReadOnly);
            var band = dataset.GetRasterBand(1);

            Debug.Assert(dataset.RasterXSize == RasterXSize || dataset.RasterXSize == RasterXSize);

            int[] value = new int[dataset.RasterXSize * dataset.RasterYSize];
            band.ReadRaster(0, 0, RasterXSize, RasterYSize, value, RasterXSize, RasterYSize, 0, 0);

            mapDatas[file] = value;
        }
    }
}